#include <iostream>
#include <sys/select.h>
#include <sys/time.h>
#include "Socket.hpp"
using namespace std;
static const uint16_t defaultport = 8888;           // 端口号
static const int fd_num_max = (sizeof(fd_set) * 8); // 最多的select监视的文件数量
int defaultfd = -1;
class SelectServer
{
public:
    SelectServer(uint16_t port = defaultport)
        :_port(port)
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            fd_array[i] = defaultfd;
        }
    }
    bool Init()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        return true;
    }
    void Recver(int fd,int pos){
        char buffer[1024];
        ssize_t n=read(fd,buffer,sizeof(buffer)-1);
        if(n>0)
        {
            buffer[n]=0;
            cout<<"get a message:"<<buffer<<endl;
        }
        else if(n==0)//对方不发信息或对方关闭了
        {
            lg(Info,"client quit ,me too ,close fd is:%d",fd);
            close(fd);
            fd_array[pos]=defaultfd;
        }
        else//读取错误
        {
            lg(Warning,"recv error:fd is:%d",fd);
            close(fd);
            fd_array[pos]=defaultfd;
        }

    }
    void PrintFd()
    {
        cout << "online fd list: ";
        for (int i = 0; i < fd_num_max; i++)
        {
            if (fd_array[i] == defaultfd)
                continue;
            cout << fd_array[i] << " ";
        }
        cout << endl;
    }
    void Accepter()
    {
        string clientip;
        uint16_t clientport=0;
        int sock=_listensock.Accept(&clientip,&clientport);//接受文件，sock是建立连接后进行通信的“文件”
        if(sock<0)return ;
        lg(Info,"accept success,%s:%d,sock:%d",clientip.c_str(),clientport,sock);
        int i=1;
        for(;i<fd_num_max;i++){
            if(fd_array[i]!=defaultfd)continue;
            else break;
        }
        if(i==fd_num_max)
        {
            lg(Warning,"server is full,close %d now!",sock);
            close(sock);
        }
        else{
            fd_array[i]=sock;
            PrintFd();
        }

    }
    void Dispatcher(fd_set&rfds)
    {
        for(int i=0;i<fd_num_max;i++)
        {
            int fd=fd_array[i];
            if(fd==defaultfd)continue;
            if(FD_ISSET(fd,&rfds))//如果就绪
            {
                if(fd==_listensock.Fd())//如果是监听的文件就绪，那么建立连接
                {
                    Accepter();
                }
                else {
                    Recver(fd,i);//读取文件
                }
            }
        }
    }
    void Start()
    {
        int listensock = _listensock.Fd();//监听文件
        fd_array[0] = listensock;
        for (;;)//不断循环看有木有事件就绪
        {
            fd_set rfds;
            FD_ZERO(&rfds);//清空一下
            int maxfd = listensock;  //目前最大的是listensock          
            for (int i =0; i < fd_num_max; i++)//遍历我们的数组，看有哪几个文件需要监视
            {
                if (fd_array[i] == defaultfd)
                    continue;
                FD_SET(fd_array[i],&rfds);    
                if(fd_array[i]>maxfd){
                    maxfd=fd_array[i];
                    lg(Info,"max fd update,max fd is %d",maxfd);
                }
            }
            timeval time={1,0};
            int n=select(maxfd+1,&rfds,NULL,NULL,&time);//监视
            switch (n)
            {
            case 0:
                cout<<"time out,timeout:"<<time.tv_sec<<time.tv_usec<<endl;
                break;
            case -1:
                cout<<"select error"<<endl;;
                break;
            default:
                cout<<"get a new link"<<endl;
                Dispatcher(rfds);//有文件就绪了，可以处理
                //处理函数
                break;
            }

        }
       
    }
    ~SelectServer()
    {
        _listensock.Close();
    }

private:
    Sock _listensock;
    uint16_t _port;
    int fd_array[fd_num_max];
};